﻿using System.Collections.Generic;
using System.IO;
using AMail.Common;
using AMail.Common.Interfaces.Data;
using AMail.Common.Interfaces.Services;
using AMail.Modules.Data.Internals;
using Elentok.Common;
using Elentok.Common.Async;

namespace AMail.Modules.Data
{
  public sealed class DataService : IDataService
  {
    #region IDataService Members

    public IMailArchive CreateArchive(string filename, string passphrase)
    {
      IMailArchive archive = new MailArchive(filename, passphrase);
      return archive;
    }

    public IMailArchive OpenArchive(string filename, string passphrase)
    {
      IMailArchive archive = new MailArchive(filename, passphrase);
      return archive;
    }

    public IMailMessage CreateMessage(byte[] data)
    {
      return new MailMessage(data);
    }

    public IMailFolder CreateFolder()
    {
      return new MailFolder();
    }

    /// <summary>
    /// This will import all of the ".eml" files in the given folder
    /// and put all of them in a new folder under <paramref name="parentFolder"/>
    /// (the root of this folder in the mail archive folder tree will be 
    ///  the name of the folder path).
    /// <para>
    /// The mail folder of the path that was imported (not connected to a parent folder)
    /// </para>
    /// </summary>
    /// <returns>The mail folder of the path that was imported</returns>
    /// <param name="sourcePath"></param>
    /// <param name="recursive">True to scan subfolders</param>
    /// <param name="progressNotifier">A progress notifier to report the progress to</param>
    /// <param name="errors">A dictionary of the errors that occured during the import</param>
    public IMailFolder ImportFolder(string sourcePath, bool recursive, IAsyncProgressNotifier progressNotifier, Dictionary<string, InvalidEmlException> errors)
    {
      if (progressNotifier != null)
        progressNotifier.NotifyProgress(0, string.Format("Scanning {0}", sourcePath), null);

      #region Scan source path
      DirectoryInfo dirInfo = new DirectoryInfo(sourcePath);
      List<FileInfo> filesToImport = new List<FileInfo>();
      FindFilesToImport(dirInfo, "*.eml", recursive, filesToImport);

      if (filesToImport.Count == 0)
        return null;
      #endregion

      IMailFolder importRootFolder = new MailFolder(dirInfo.Name);

      int index = 0;
      foreach (FileInfo file in filesToImport)
      {
        #region Notify on the current progress
        if (progressNotifier != null)
          progressNotifier.NotifyProgress(index * 100 / filesToImport.Count,
            string.Format("Importing file {0}/{1}:\r\n{2}", index + 1, filesToImport.Count, file.FullName), null);
        #endregion

        string relativePath = file.DirectoryName.Substring(dirInfo.FullName.Length);
        IMailFolder folder = importRootFolder.GetOrCreateSubfolder(relativePath);
        
        IMailMessage message = null;
        byte[] emlBytes = File.ReadAllBytes(file.FullName);
        try
        {
          message = new MailMessage(emlBytes);
        }
        catch (InvalidEmlException ex)
        {
          errors.Add(file.FullName, ex);
        }

        if (message != null)
        {
          message.ParentFolder = folder;
        }

        index++;
      }

      if (importRootFolder.Subfolders.Count == 0 &&
        importRootFolder.Messages.Count == 0)
        return null;

      return importRootFolder;
    }

    #endregion

    #region Helper Methods
    private void FindFilesToImport(DirectoryInfo dirInfo, string pattern, bool recursive, List<FileInfo> outFiles)
    {
      foreach (FileInfo fileInfo in dirInfo.GetFiles(pattern))
      {
        outFiles.Add(fileInfo);
      }

      if (!recursive)
        return;

      foreach (DirectoryInfo subdirInfo in dirInfo.GetDirectories())
      {
        FindFilesToImport(subdirInfo, pattern, true, outFiles);
      }
    }
    #endregion

  }
}
